How to format InstallDate property used in Select-Object? - powershell

The InstallDate property used in the below code -
$InstalledProgram | Select-Object DisplayName, DisplayVersion, Publisher,
InstallDate | Format-Table –AutoSize
$logDisplayName = $InstalledProgram.DisplayName
$logPublisher = $InstalledProgram.Publisher
$logVersion = $InstalledProgram.DisplayVersion
$logInstallDate= $InstalledProgram.InstallDate
It displays the date of an installed application in this format 20170921 but i want it to be displayed in 21/09/2017 i.e DD/MM/YYYY format. How can i format it?
Below is the Entire Code which is used to copy the output to log file:-
Clear-Host
$scriptPath = $PSScriptRoot
$logFilePath= Join-path $scriptPath "POCTestResults.log"
# If log file exists, then clear its contents
if (Test-Path $logFilePath)
{
clear-content -Path $logFilePath
}
# It displays the date and time of execution of powershell script in log file.
$log = "Date Of Testing: {0} " -f (Get-Date)
$logString = "Process Started."
add-content -Path $logFilePath -Value $log -Force
add-content -Path $logFilePath -Value $logString -Force
add-content -Path $logFilePath -Value "`n" -Force
# Validate ADD/Remove Program list
# FUNCTION DEFINITIONS
function Log-InstalledProgram($InstalledProgram, $LogFilePath)
{
#$InstalledProgram | Select-Object DisplayName, DisplayVersion, Publisher, InstallDate |
#Format-Table –AutoSize
$InstalledProgram | Select-Object DisplayName, DisplayVersion, Publisher, #{Name="InstallDate"; Expression={([datetime]::ParseExact($_.InstallDate, 'yyyyMMdd', $null)).toshortdatestring()}} | Format-Table –AutoSize
$logDisplayName = $InstalledProgram.DisplayName
$logPublisher = $InstalledProgram.Publisher
$logVersion = $InstalledProgram.DisplayVersion
$logInstallDate= $InstalledProgram.InstallDate
add-content -Path $LogFilePath -Value "Product Name: $logDisplayName" -Force
add-content -Path $LogFilePath -Value "Publisher: $logPublisher" -Force
add-content -Path $LogFilePath -Value "Version: $logVersion" -Force
add-content -Path $LogFilePath -Value "InstallDate: $logInstallDate" -Force
add-content -Path $LogFilePath -Value "`n" -Force
}
add-content -Path $logFilePath -Value "`n" -Force
add-content -Path $logFilePath -Value "Add/Remove Programs :" -Force
add-content -Path $logFilePath -Value "`n" -Force
$InstalledPrograms = Get-ItemProperty HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*
foreach ($InstalledProgram in $InstalledPrograms )
{
foreach ($displayName in "IntelliMatch Operational Control","intelliSuite Management Studio", "SunGard System Analyzer", "STeP")
{
if(($InstalledProgram.DisplayName -ne $Null) -and ($InstalledProgram.DisplayName.Contains($displayName)))
{
Log-InstalledProgram $InstalledProgram $logFilePath
}
}
}
This is script i have used.

Use [datetime]::ParseExact() method and calculated properties to retrieve a datetime format in the Select-Object and format it in a short date string with .toshortdatestring() :
$InstalledProgram | Select-Object DisplayName, DisplayVersion, Publisher, #{Name="InstallDate"; Expression={([datetime]::ParseExact($_.InstallDate, 'yyyyMMdd', $null)).toshortdatestring()}} | Format-Table –AutoSize
$logDisplayName = $InstalledProgram.DisplayName
$logPublisher = $InstalledProgram.Publisher
$logVersion = $InstalledProgram.DisplayVersion
$logInstallDate= $InstalledProgram.InstallDate

Related

How can I detect the autorun process with powershell?

I'm going to check the PC using powershell.
The purpose is to detect automatic execution malware.
If there is a new process after execution, it shows a new process. Then, I want to create a code that allows users to identify and detect whether it is a malicious process.
Function Reg {
$key_1 = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
$key_2 = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce"
$key_3 = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
$key_4 = "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce"
$p1 = Get-Item -Path $key_1 | Select-Object -ExpandProperty Property
$p2 = Get-Item -Path $key_2 | Select-Object -ExpandProperty Property
$p3 = Get-Item -Path $key_3 | Select-Object -ExpandProperty Property
$p4 = Get-Item -Path $key_4 | Select-Object -ExpandProperty Property
$result = $p1 + $p2 + $p3 + $p4
$result
}
Function Check {
$file = "C:\study\project\PC_Check\result.txt"
if ( -not (Test-Path $file)) {
Reg | Out-File -FilePath "C:\study\project\PC_Check\result.txt"
}
else {
if ((Reg) -eq (Get-Content $file)) {
Write-Host "No new process."
}
else {
Write-Host "New process detected."
Reg | Out-File -FilePath "C:\study\project\PC_Check\result.txt"
}
}
}
Check
The problem with my code is that there is no comparison between the executed output and the contents of the first file.
I want to print out a new process while comparing the current outputs and file contents.
(Reg) -eq (Get-Content $file)
I think this compare part is wrong, how should I correct it?
Thank you for your time to read this and Have a nice day!
As per my comment. One way to refactor this is as follows. Tweak as needed.
Clear-Host
# Refactor to get all Autorun details
Function Get-AutorunDetail
{
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce',
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce' |
ForEach-Object {(Get-Item -Path $PSitem).Property}
}
Get-AutorunDetail |
Out-Null
Function Write-AutorunResultsFile
{
# Check if file path exists
$AutorunResultsFile = 'D:\study\project\PC_Check'
# If not, create the path and the new file
if ( -not (Test-Path -Path "$AutorunResultsFile\AutorunResultsFile.txt"))
{
New-Item -Path $AutorunResultsFile -ItemType File -Name 'AutorunResultsFile.txt' -Force |
Out-Null
# Add the Autorun detail to the new file
Get-AutorunDetail |
ForEach-Object {Add-Content -Path "$AutorunResultsFile\AutorunResultsFile.txt" -Value $PSitem}
}
else
{
if (Compare-Object -ReferenceObject {Get-AutorunDetail} -DifferenceObject (Get-Content -Path "$AutorunResultsFile\AutorunResultsFile.txt"))
{Add-Content -Path "$AutorunResultsFile\AutorunResultsFile.txt" -Value 'No new process.'}
else
{
'New process detected.'
Get-AutorunDetail |
ForEach-Object {Add-Content -Path "$AutorunResultsFile\AutorunResultsFile.txt" -Value $PSitem}
}
}
}
Write-AutorunResultsFile
Again, this is just one way, there are always more and/or better ways - but I'll leave them to you to research or others to chime in.
Updated
Clear-Host
# Refactor to get all Autorun details
Function Get-AutorunDetail
{
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce',
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run',
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce' |
ForEach-Object {(Get-Item -Path $PSitem).Property}
}
Get-AutorunDetail |
Out-Null
Function Write-AutorunResultsFile
{
# Check if file path exists
$AutorunResultsFile = 'D:\study\project\PC_Check'
# If not, create the path and the new file
if ( -not (Test-Path -Path "$AutorunResultsFile\AutorunResultsFile.txt"))
{
New-Item -Path $AutorunResultsFile -ItemType File -Name 'AutorunResultsFile.txt' -Force |
Out-Null
# Add the Autorun detail to the new file
Get-AutorunDetail |
ForEach-Object {Add-Content -Path "$AutorunResultsFile\AutorunResultsFile.txt" -Value $PSitem}
}
else
{
if ($AutorunDetails = (Compare-Object -ReferenceObject (Get-AutorunDetail) -DifferenceObject (Get-Content -Path "$AutorunResultsFile\AutorunResultsFile.txt")) -match '<=')
{
Add-Content -Path "$AutorunResultsFile\AutorunResultsFile.txt" -Value 'New process detected.'
Add-Content -Path "$AutorunResultsFile\AutorunResultsFile.txt" -Value ($AutorunDetails.InputObject | Select-Object -Last 1)
}
else
{Add-Content -Path "$AutorunResultsFile\AutorunResultsFile.txt" -Value 'No new process detected.'}
}
}
Write-AutorunResultsFile
# Results when altering the registry key
<#
Security...
Tablet...
Display...
ms...
OneDrive
Micros...
CiscoM...
...
Docker Desktop
GoToMeeting
No new process detected.
New process detected.
test
No new process detected.
New process detected.
test1
No new process detected.
New process detected.
test2
#>

How to make Powershell to output the result to a csv

I am trying to output to a csv file the result that I am getting from "Get-ChildItem"
I need to save only the LastWriteTime and the Name.
This is the Get-ChildItem output
I am trying something like
$pc = Get-WmiObject Win32_ComputerSystem
$file = Get-ChildItem -Path S:\Docker\RCT\repo\*xml -Recurse -Force
$DeviceObj = New-Object PSObject -Property #{
DeviceName = $pc.Name
FileName = $file.Name
FileDate = $file.LastWriteTime
}
$DeviceObjList += $DeviceObj
$DeviceObjList | Export-Csv -Path "$current_path\FileStatus.csv" -NoTypeInformation -Encoding UTF8
But my csv is not saving the file name and also the timestamp
Use a ForEach-Object to loop though your $file object
$pc = Get-WmiObject Win32_ComputerSystem
$file = Get-ChildItem -Path S:\Docker\RCT\repo\*xml -Recurse -Force
$file | ForEach-Object {
$DeviceObj = New-Object PSObject -Property #{
DeviceName = $pc.Name
FileName = $_.Name
FileDate = $_.LastWriteTime
}
$DeviceObjList += $DeviceObj
}
$DeviceObjList | Export-Csv -Path "$current_path\FileStatus.csv" -NoTypeInformation -Encoding UTF8
..but in fact, this is more efficient:
$pc = Get-WmiObject Win32_ComputerSystem
$file = Get-ChildItem -Path S:\Docker\RCT\repo\*xml -Recurse -Force
$DeviceObjList = $file | ForEach-Object {
[pscustomobject]#{
DeviceName = $pc.Name
FileName = $_.Name
FileDate = $_.LastWriteTime
}
}
$DeviceObjList | Export-Csv -Path "$current_path\FileStatus.csv" -NoTypeInformation -Encoding UTF8
You Don't need WMI to get the computer name, use the built-in variable $env:COMPUTERNAME
Use Calculated Properties to add the Computer name to the results.
Iteration not required here, just add the Export-Csv to the pipeline
So you can do that:
$file = Get-ChildItem -Path S:\Docker\RCT\repo\*xml -Recurse -Force
$File | Select #{N="DeviceName";E={$env:COMPUTERNAME}},Name,LastWriteTime |
Export-Csv -Path "$current_path\FileStatus.csv" -NoTypeInformation -Encoding UTF8
And if you want to make it shorter, you can use aliases and don't define any variables
gci S:\Docker\RCT\repo\*xml -R -Fo |
select #{N="DeviceName";E={$env:COMPUTERNAME}},Name,LastWriteTime |
epcsv "$current_path\FileStatus.csv" -NoT -En UTF8

PowerShell BitsTransfer use file names from variable as source

I am new to PowerShell and I get a lot done using this forum along with other internet searched answers but this one is getting the better of me. I have a script that compares two folders and the part where I'm having problems I cannot get the BitsTransfer source to work. $Differences identifies files from the source folder that are not in the target folder by modified date. I want the BitsTransfer to move the files identified by $Differences but I'm not having any luck getting that behavior. The operation works when I use "Copy-Item -Path $Differences -Destination $Local –Force" instead but i want the progress bar BitsTransfer Uses. The code i am using is as follows
$Local = 'c:\test\local\'
$Remote = 'c:\test\server\'
$Target = Get-ChildItem -Path $Local -File
$Source = Get-ChildItem -Path $Remote -File
Import-Module BitsTransfer
Set-Location $Remote
filter timestamp {"$(Get-Date -Format g): $_"}
if ($Target -eq $null) {
$bitsjob = Start-BitsTransfer -Source $Remote\*.* -Destination $Local
Write-Output "$Local Folder Empty" | timestamp | Out-File -Encoding Ascii -append "D:\Mitek\DCS Stuff\Display PC Scripts\test\log.txt"
Rename-Item -Path "D:\Mitek\DCS Stuff\Display PC Scripts\test\RemoteComplete.bat" -NewName "Remote.bat"
Exit
} Else {
if ($Target -ne $null){
Compare-Object $Source $Target -Property Name -PassThru | Where-Object {$_.SideIndicator -eq "=>"} | % {
if(-not $_.FullName.PSIsContainer) {
Write-Output "Removed From $Local" | timestamp | Out-File -Encoding Ascii -append "D:\Mitek\DCS Stuff\Display PC Scripts\test\log.txt"
Remove-Item -Path $_.FullName -Force -ErrorAction SilentlyContinue}}}}
$Differences = Compare-Object -ReferenceObject $Source -DifferenceObject $Target -Property LastWriteTime -PassThru
$Differences | Group-Object Name | Select -ExpandProperty Group | Sort-Object LastWriteTime | Select-Object -Last 1
if ($Differences -ne $null) {
foreach ($file in $Differences) {
#Copy-Item -Path $Differences -Destination $Local –Force
Start-BitsTransfer -Source $Differences -Destination $Local
Write-Output "Copied to $Local" | timestamp | Out-File -Encoding Ascii -append "D:\Mitek\DCS Stuff\Display PC Scripts\test\log.txt"
Rename-Item -Path "D:\Mitek\DCS Stuff\Display PC Scripts\test\RemoteComplete.bat" -NewName "Remote.bat"}
} Else {
Write-Output "$Local and $Remote are Equal" | timestamp | Out-File -Encoding Ascii -append "D:\Mitek\DCS Stuff\Display PC Scripts\test\log.txt"}`
I got the issue figured out with some looping behavior the code used to resolve the issue is bellow for those who may find this helpful in the future...
$Local = 'C:\test\local\'
$Remote = 'C:\test\server\'
$Target = Get-ChildItem -Path $Local -File
$Source = Get-ChildItem -Path $Remote -File
$One = 1
Set-Location $Remote
filter timestamp {"$(Get-Date -Format g): $_"}
if ($Target -eq $null) {
$TotalA = $Source | Measure | Select-Object -ExpandProperty Count
echo "Total Number of Files to be Copied= $TotalA"
echo "---------------------------------------------------------------"
Write-Output "$Local Folder Empty" | timestamp | Out-File -Encoding Ascii -append "D:\Mitek\DCS Stuff\Display PC Scripts\test\log.txt"
Start-BitsTransfer -Source $Remote\*.* -Destination $Local -Description "Copying $TotalA Files"
Rename-Item -Path "C:\test\RemoteComplete.bat" -NewName "Remote.bat"
exit
} Else {
if ($Target -ne $null){
Compare-Object $Source $Target -Property Name -PassThru | Where-Object {$_.SideIndicator -eq "=>"} | % {
if(-not $_.FullName.PSIsContainer) {
Write-Output "Removed From $Local" | timestamp | Out-File -Encoding Ascii -append "D:\Mitek\DCS Stuff\Display PC Scripts\test\log.txt"
Remove-Item -Path $_.FullName -Force -ErrorAction SilentlyContinue}}}}
$Differences = Compare-Object -ReferenceObject $Source -DifferenceObject $Target -Property LastWriteTime -PassThru
if ($Differences -ne $null) {
$TotalB=$Differences | Group-Object Name | Select -ExpandProperty Group | Sort-Object Name | Measure | Select-Object -ExpandProperty Count
echo "Total Number of Files to be Copied= $TotalB"
Write-Output "Copied to $Local" | timestamp | Out-File -Encoding Ascii -append "D:\Mitek\DCS Stuff\Display PC Scripts\test\log.txt"
do {
$Tar = Get-ChildItem -Path $Local -File
$Src = Get-ChildItem -Path $Remote -File
$Diffs = Compare-Object -ReferenceObject $Src -DifferenceObject $Tar -Property LastWriteTime -PassThru
$ListB=$Diffs | Group-Object Name | Select -ExpandProperty Group | Sort-Object Name | Select-Object -First 1
if ($ListB -ne $null) {
echo "---------------------------------------------------------------"
$Rmn=$Diffs | Group-Object Name | Select -ExpandProperty Group | Sort-Object Name | Measure | Select-Object -ExpandProperty Count
$RemainB = $Rmn - $One
Start-BitsTransfer -Source $ListB -Destination $Local -Description "$RemainB Files Remain Copying - $List" }}
Until ($ListB -eq $null)
Rename-Item -Path "C:\test\RemoteComplete.bat" -NewName "Remote.bat"
} Else {
Write-Output "$Local and $Remote are Equal" | timestamp | Out-File -Encoding Ascii -append "D:\Mitek\DCS Stuff\Display PC Scripts\test\log.txt"}

Powershell : Get directory permission recursively

I am trying to get the CSV output like below so that user can filter in excel.
Folder,Group,Permission
I:\Folder1,corp\group1,ReadData,ExecuteFile,Synchronize
I:\Folder1\Folder2,corp\group2,ReadData,ExecuteFile,Synchronize
Below is what is started with. Very inefficient and does not give the desired CSV output. Will appreciate any help.
$output_file = $(get-date -f MM-dd-yyyy_HH_mm_ss)+'.txt'
"{0},{1},{2}" -f "Folder","Groups","Permissions"| add-content -path $output_file
$file_content = ''
function GetFolders($path = $pwd)
{
if( $path -ne $null) {
$new_row = Get-ACL $path | select -ExpandProperty Access | Where-Object IdentityReference -Like "CORP*" | SELECT $path, IdentityReference, FileSystemRights | Format-Table -HideTableHeaders | Out-String
$fileContent += $new_row
$fileContent | add-content -path $output_file
foreach ($item in Get-ChildItem $path)
{
if (Test-Path $item.FullName -PathType Container)
{
Write-Output $item.FullName
GetFolders $item.FullName
$new_row = Get-ACL $item.FullName | select -ExpandProperty Access | Where-Object IdentityReference -Like "CORP*" | SELECT $item.FullName, IdentityReference, FileSystemRights | Format-Table -HideTableHeaders | Out-String
$fileContent += $new_row
$fileContent | add-content -path $output_file
}
}
}
}
GetFolders "J:\"
You were on the right path but went off-course a bit.
Set-Content -Path $FileName -Value 'Folder,Groups,Permissions'
(Get-Acl -Path $Path).Access |
Where-Object -Property IdentityReference -like 'corp*' |
ForEach-Object {
Add-Content -Path $FileName -Value "$Path,$($_.IdentityReference),$($_.FileSystemRights -replace '\s')"
}
To be a little more fancy (if you want to edit the code in the subexpressions or something of that nature)
$Val = {"$Path,$($_.IdentityReference),$($_.FileSystemRights -replace '\s')"}
... -Value (&$Val) ...

System.Object[] - when file names are same

I have files in E:\MyFiles\ and E:\MyFiles\August. I am using PowerShell to store the file paths in a csv file (E:\CSVPaths.csv).
This is my script:
$exclude = #(".html", ".tt", ".xaml", ".csproj", ".sln", ".xml", ".cmd", ".txt",".svn")
"DirectoryPath, SourceFileName" | Out-File -FilePath "E:\CSVPaths.csv" -Encoding ASCII
$table = (get-childitem -recurse "E:\MyFiles" -File -ErrorAction SilentlyContinue | Where-Object { $exclude -notcontains $_.Extension }).Fullname
foreach ($row in $table)
{
$file=Get-ChildItem -recurse $row
$fileObject = new-object PSObject
$fileObject | add-member -membertype NoteProperty -name "DirectoryPath" -Value $file.DirectoryName
$fileObject | add-member -membertype NoteProperty -name "SourceFileName" -Value $file.Name
$newrow=$fileObject
Export-Csv "E:\CSVPaths.csv" -inputobject $newrow -append -Force
}
In both E:\MyFiles and E:\MyFiles\August folders, there are files with same name (example: Audit_Report.csv). While exporting to csv they are stored as System.Object[] in DirectoryPath and SourceFileName which is shown below:
DirectoryPath SourceFileName
System.Object[] System.Object[]
E:\MyFiles\August Audit_Report.csv
Please help to fix this issue.
There is no need to use a loop to get the output your after AFAICS.
$exclude = #(".html", ".tt", ".xaml", ".csproj", ".sln", ".xml", ".cmd", ".txt",".svn")
"DirectoryPath, SourceFileName" | Out-File -FilePath "E:\CSVPaths.csv" -Encoding ASCII
Get-ChildItem -recurse "E:\MyFiles" -File -ErrorAction SilentlyContinue |
Where-Object { $exclude -notcontains $_.Extension } |
Select-Object #{n="SoureFileName";e={$_.Name}},#{n="DirectoryPath";e={$_.DirectoryName}} |
Export-csv "E:\CSVPaths.csv" -Force -NoTypeInformation
# NB: The "-NoTypeInformation" is an assumption - remove if you what type info.