Writing an output on a .txt file on Powershell - powershell

I found a little script to get all the local groups and members and it's working perfectly but I need to write the output on PowerShell.
Trap {"Error: $_"; Break;}
function EnumLocalGroup($LocalGroup) {
$Group = [ADSI]"WinNT://$strComputer/$LocalGroup,group"
"`r`n" + "Group: $LocalGroup"
$Members = #($Group.psbase.Invoke("Members"))
foreach ($Member In $Members) {
$Name = $Member.GetType().InvokeMember("Name", 'GetProperty', $Null, $Member, $Null)
$Name
}
}
$strComputer = gc env:computername
"Computer: $strComputer"
$computer = [adsi]"WinNT://$strComputer"
$objCount = ($computer.PSBase.Children | Measure-Object).Count
$i = 0
foreach ($adsiObj in $computer.PSBase.Children) {
switch -regex ($adsiObj.PSBase.SchemaClassName) {
"group" {
$group = $adsiObj.Name
EnumLocalGroup $group
}
}
$i++
}
I already tried this:
function EnumLocalGroup($LocalGroup) | Out-File -FilePath "E:\PS\Malik\group.txt"
But the code won't start if I do that. I also tried to use this whole Out-File line at the end of the code after the } but doesn't work either and this is the only solution I find on Internet.

If you want to incorporate logging into a function you need to put it into the function body, e.g.
function EnumLocalGroup($LocalGroup) {
....
$foo = 'something'
$foo # output returned by function
$foo | Add-Content 'log.txt' # output to log file
...
}
or
function EnumLocalGroup($LocalGroup) {
...
$foo = 'something'
$foo | Tee-Object 'log.txt' -Append # output goes to log file and StdOut
...
}
Otherwise you have to do the logging when you call the function:
EnumLocalGroup $group | Add-Content 'C:\log.txt'

Related

Powershell - Exchange JSON output without needing to write to a file

EDIT: Added Setupconfigfiles.ps1
I'm a bit new to detailed scripting so please bear with me.
I have two Powershell scripts
Setupconfigfiles.ps1 generates JSON output to be fed to an API.
Script2 uses that JSON data to execute API commands.
Script 2 can call setupconfigfiles.ps1 as indicated below and use the output data.
.\SetupConfigFiles.ps1 -type $Type -outfile .\Templist.json
$servers = Get-Content -Raw -Path .\templist.json | ConvertFrom-Json
setupconfigfiles.ps1:
param (
# If this parameter is set, format the output as csv.
# If this parameter is not set, just return the output so that the calling program can use the info
[string]$outfile,
# this parameter can be 'production', 'development' or 'all'
[string]$type
)
enum MachineTypes {
production = 1
development = 2
all = 3
}
$Servers = Get-ADObject -Filter 'ObjectClass -eq "computer"' -SearchBase 'Obfuscated DSN' | Select-Object Name
$output = #()
$count = 0
# Set this to [MachineTypes]::production or [MachineTypes]::development or [MachineTypes]::all
if ($type -eq "all") {
$server_types = [MachineTypes]::all
}
ElseIf ($type -eq "production") {
$server_types = [MachineTypes]::production
}
else {
$server_types = [MachineTypes]::development
}
ForEach ($Server in $Servers)
{
$count = $count + 1
$this_server = #{}
$this_server.hostname = $Server.Name
$this_server.id = $count
$this_server."site code" = $this_server.hostname.substring(1,3)
$this_server."location code" = $this_server.hostname.substring(4,2)
if ($this_server.hostname.substring(7,1) -eq "P") {
$this_server.environment = "Production"
}
ElseIf ($this_server.hostname.substring(7,1) -eq "D") {
$this_server.environment = "Development"
}
Else {
$this_server.environment = "Unknown"
}
if (($server_types -eq [MachineTypes]::production ) -and ($this_server.environment -eq "Production")) {
$output += $this_server
}
ElseIf (($server_types -eq [MachineTypes]::development ) -and ($this_server.environment -eq "Development")) {
$output += $this_server
}
Else {
if ($server_types -eq [MachineTypes]::all ) {
$output += $this_server
}
}
}
if ($outfile -eq "")
{
ConvertTo-Json $output
}
else {
ConvertTo-Json $output | Out-File $outfile
}
How can I do it without needing to write to the Templist.json file?
I've called this many different ways. The one I thought would work is .\SetupConfigFiles.ps1 $servers
Y'all are great. #Zett42 pointed me in a direction and #Mathias rounded it out.
The solution was to change:
"ConvertTo-Json $output" to "Write-Output $output"
Then it's handled in the calling script.
thanks!

Comparing two text files and output the differences in Powershell

So I'm new to the Powershell scripting world and I'm trying to compare a list of IPs in text file against a database of IP list. If an IP from (file) does not exist in the (database) file put it in a new file, let's call it compared.txt. When I tried to run the script, I didn't get any result. What am I missing here?
$file = Get-Content "C:\Users\zack\Desktop\file.txt"
$database = Get-Content "C:\Users\zack\Desktop\database.txt"
foreach($line1 in $file){
$check = 0
foreach($line2 in $database)
{
if($line1 != $line2)
{
$check = 1
}
else
{
$check = 0
break
}
}
if ($check == 1 )
{
$line2 | Out-File "C:\Users\zack\Desktop\compared.txt"
}
}
There is a problem with your use of PowerShell comparison operators unlike in C#, equality and inequality are -eq and -ne, and since PowerShell is a case insensitive language, there is also -ceq and -cne.
There is also a problem with your code's logic, a simple working version of it would be:
$database = Get-Content "C:\Users\zack\Desktop\database.txt"
# iterate each line in `file.txt`
$result = foreach($line1 in Get-Content "C:\Users\zack\Desktop\file.txt") {
# iterate each line in `database.txt`
# this happens on each iteration of the outer loop
$check = foreach($line2 in $database) {
# if this line of `file.txt` is the same as this line of `database.txt`
if($line1 -eq $line2) {
# we don't need to keep checking, output this boolean
$true
# and break the inner loop
break
}
}
# if above condition was NOT true
if(-not $check) {
# output this line, can be `$line1` or `$line2` (same thing here)
$line1
}
}
$result | Set-Content path\to\comparisonresult.txt
However, there are even more simplified ways you could achieve the same results:
Using containment operators:
$database = Get-Content "C:\Users\zack\Desktop\database.txt"
$result = foreach($line1 in Get-Content "C:\Users\zack\Desktop\file.txt") {
if($line1 -notin $database) {
$line1
}
}
$result | Set-Content path\to\comparisonresult.txt
Using Where-Object:
$database = Get-Content "C:\Users\zack\Desktop\database.txt"
Get-Content "C:\Users\zack\Desktop\file.txt" | Where-Object { $_ -notin $database } |
Set-Content path\to\comparisonresult.txt
Using a HashSet<T> and it's ExceptWith method (Note, this will also get rid of duplicates in your file.txt):
$file = [System.Collections.Generic.HashSet[string]]#(
Get-Content "C:\Users\zack\Desktop\file.txt"
)
$database = [string[]]#(Get-Content "C:\Users\zack\Desktop\database.txt")
$file.ExceptWith($database)
$file | Set-Content path\to\comparisonresult.txt

Powershell - Store hash table in file and read its content

As follow-up, suggested by Doug, on my previous question on anonymizing file (
PowerShell - Find and replace multiple patterns to anonymize file) I need to save all hash tables values in single file "tmp.txt" for further processing.
Example: after processing the input file with string like:
<requestId>>qwerty-qwer12-qwer56</requestId>
the tmp.txt file contains:
qwerty-qwer12-qwer56 : RequestId-1
and this is perfect. The problem is when working with many strings, in the tmp.txt file there are more pairs than there should be. In my example below in tmp.txt I should see 4 times the "RequestId-x" but there are 6. Also when there are 2 or more "match" on the same line, only the first is updated/replaced. Any idea from where these extra lines comes from? Any why the script doesn't continue to check till the end of the same line?
Here is my test code:
$log = "C:\log.txt"
$tmp = "C:\tmp.txt"
Clear-Content $log
Clear-Content $tmp
#'
<requestId>qwerty-qwer12-qwer56</requestId>qwertykeyId>Qwd84lPhjutf7Nmwr56hJndcsjy34imNQwd84lPhjutZ7Nmwr56hJndcsjy34imNPozDr5</ABC reportId>poGd56Hnm9q3Dfer6Jh</msg:reportId>
<requestId>zxcvbn-zxcv12-zxcv56</requestId>
<requestId>qwerty-qwer12-qwer56</requestId>abcde reportId>plmkjh8765FGH4rt6As</msg:reportId>
<requestId>1234qw-12qw12-12qw56</requestId>
keyId>Qwd84lPhjutf7Nmwr56hJndcsjy34imNQwd84lPhjutZ7Nmwr56hJndcsjy34imNPozDr5</
keyId>Qwd84lPhjutf7Nmwr56hJndcsjy34imNQwd84lPhjutZ7Nmwr56hJndcsjy34imNPozDr5</
keyId>Zdjgi76Gho3sQw0ib5Mjk3sDyoq9zmGdZdjgi76Gho3sQw0ib5Mjk3sDyoq9zmGdLkJpQw</
reportId>plmkjh8765FGH4rt6As</msg:reportId>
reportId>plmkjh8765FGH4rt6As</msg:reportId>
reportId>poGd56Hnm9q3Dfer6Jh</msg:reportId>
'# | Set-Content $log -Encoding UTF8
$requestId = #{
Count = 1
Matches = #()
}
$keyId = #{
Count = 1
Matches = #()
}
$reportId = #{
Count = 1
Matches = #()
}
$output = switch -Regex -File $log {
'(\w{6}-\w{6}-\w{6})' {
if(!$requestId.matches.($matches.1))
{
$req = $requestId.matches += #{$matches.1 = "RequestId-$($requestId.count)"}
$requestId.count++
$req.keys | %{ Add-Content $tmp "$_ : $($req.$_)" }
}
$_ -replace $matches.1,$requestId.matches.($matches.1)
}
'keyId>(\w{70})</' {
if(!$keyId.matches.($matches.1))
{
$kid = $keyId.matches += #{$matches.1 = "keyId-$($keyId.count)"}
$keyId.count++
$kid.keys | %{ Add-Content $tmp "$_ : $($kid.$_)" }
}
$_ -replace $matches.1,$keyId.matches.($matches.1)
}
'reportId>(\w{19})</msg:reportId>' {
if(!$reportId.matches.($matches.1))
{
$repid = $reportId.matches += #{$matches.1 = "Report-$($reportId.count)"}
$reportId.count++
$repid.keys | %{ Add-Content $tmp "$_ : $($repid.$_)" }
}
$_ -replace $matches.1,$reportId.matches.($matches.1)
}
default {$_}
}
$output | Set-Content $log -Encoding UTF8
Get-Content $log
Get-Content $tmp
If you don't care about the order in which they were found, which I assume you wouldn't if you don't want duplicates, just export them all at the end. I would still keep them in an "object" form so you can easily import/export them. Csv would be an ideal candidate for the data.
$requestId,$keyid,$reportid | Foreach-Object {
foreach($key in $_.matches.keys)
{
[PSCustomObject]#{
Original = $key
Replacement = $_.matches.$key
}
}
}
The data output to console for this example
Original Replacement
-------- -----------
qwerty-qwer12-qwer56 RequestId-1
zxcvbn-zxcv12-zxcv56 RequestId-2
1234qw-12qw12-12qw56 RequestId-3
Qwd84lPhjutf7Nmwr56hJndcsjy34imNQwd84lPhjutZ7Nmwr56hJndcsjy34imNPozDr5 keyId-1
Zdjgi76Gho3sQw0ib5Mjk3sDyoq9zmGdZdjgi76Gho3sQw0ib5Mjk3sDyoq9zmGdLkJpQw keyId-2
poGd56Hnm9q3Dfer6Jh Report-1
plmkjh8765FGH4rt6As Report-2
Just pipe it into Export-Csv
$requestId,$keyid,$reportid | Foreach-Object {
foreach($key in $_.matches.keys)
{
[PSCustomObject]#{
Original = $key
Replacement = $_.matches.$key
}
}
} | Export-Csv $tmp -NoTypeInformation

How to dump the foreach loop output into a file in PowerShell?

I have wrote the following script to read the CSV file to perform the custom format of output.
Script is below:
$Content = Import-Csv Alert.csv
foreach ($Data in $Content) {
$First = $Data.DisplayName
$Second = $Data.ComputerName
$Third = $Data.Description
$Four = $Data.Name
$Five = $Data.ModifiedBy
$Six = $Data.State
$Seven = $Data.Sev
$Eight = $Data.Id
$Nine = $Data.Time
Write-Host "START;"
Write-Host "my_object="`'$First`'`;
Write-Host "my_host="`'$Second`'`;
Write-Host "my_long_msg="`'$Third`'`;
Write-Host "my_tool_id="`'$Four`'`;
Write-Host "my_owner="`'$Five`'`;
Write-Host "my_parameter="`'$Four`'`;
Write-Host "my_parameter_value="`'$Six`'`;
Write-Host "my_tool_sev="`'$Seven`'`;
Write-Host "my_tool_key="`'$Eight`'`;
Write-Host "msg="`'$Four`'`;
Write-Host "END"
}
The above script executing without any error.
Tried with Out-File and redirection operator in PowerShell to dump the output into a file, but I'm not finding any solution.
Write-Host writes to the console. That output cannot be redirected unless you run the code in another process. Either remove Write-Host entirely or replace it with Write-Output, so that the messages are written to the Success output stream.
Using a foreach loop also requires additional measures, because that loop type doesn't support pipelining. Either run it in a subexpression:
(foreach ($Data in $Content) { ... }) | Out-File ...
or assign its output to a variable:
$output = foreach ($Data in $Content) { ... }
$output | Out-File ...
Another option would be replacing the foreach loop with a ForEach-Object loop, which supports pipelining:
$Content | ForEach-Object {
$First = $_.DisplayName
$Second = $_.ComputerName
...
} | Out-File ...
Don't use Out-File inside the loop, because repeatedly opening the file will perform poorly.

how to use out-file with a foreach loop

$web = Get-SPWeb http://mysite
ForEach($list in $web.Lists)
{
if($list.BaseType -eq "DocumentLibrary")
{
Write-Host $list.Fields
if($list.Fields.ContainsField("marking") -eq $true)
{
Write-Host "found" $list.Title
}
}
} | Out-File test.txt
I have this code, which doesn't work due to write-host outputting to command line so obviously it won't write to the file.
How can I make it so it doesn't output to the command line but just outputs all the items found to the text file
Place your Out-File with the -Append switch after the lines you want to write, and take out theWrite-Host.
This would be a cleaner way to do it and probably faster. You're not going to get the carriage
return you're getting in your script after $list.Fields but I suspect you don't want that anyway
$doclibraries = (Get-SPWeb http://mysite).Lists | where {$_.BaseType -eq 'DocumentLibrary'}
foreach ($library in $doclibraries) {
$line = $library.Fields
if ($Line.ContainsField('marking')) {
Add-Content -Value "$line found $($library.title)" -Path test.txt
}
}