The script below asks for the $tag1 variable and uses that, but instead of entering in 1 variable at a time, I want to load a text file with many variables. I know you can use Get-Content c:\scripts\test.txt | Foreach-Object but I am not sure how to use it in this situation.
Get-Content C:\Users\ajstepanik\Desktop\tags.txt | Foreach-Object { write-host $_
#Windows XP
$reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $tag1)
$key = $reg.OpenSubKey('SOFTWARE\Microsoft\Windows NT\CurrentVersion\WinLogon')
$winxp = $key.GetValue('DefaultUserName') -replace '^.*?\\'
#Windows 7
$reg1 = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $tag1)
$key1 = $reg1.OpenSubKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Authentication\LogonUI')
$win7 = $key1.GetValue('LastLoggedOnUser') -replace '^.*?\\'
set-alias psloggedon 'C:\Users\ajstepanik\Desktop\PSTools\PsLoggedon.exe'
echo "Windows XP"
echo "----------"
echo $winxp
"`n"
echo "Windows 7"
echo "----------"
echo $win7
"`n"
$pstools = psloggedon \\$tag1
echo $pstools
}
I'm not going to attempt to rewrite your script for you, but you need to do something like this:
$fileinput = Get-Content c:\tags.txt
foreach ($tag in $fileinput)
{
Write-Host $tag
# Or whatever it is you're trying to do here
}
Related
This question already has an answer here:
Pass object[] into a function in PowerShell
(1 answer)
Closed 4 years ago.
I'm building a tool that will scan my files and a friend's files. We will use this to make sure we have the same files in our databases. The script I have so far has a variable input issue. For some reason, the PowerShell script fails on my drive letter input. Anyone have any ideas?
Here is my script:
{
function Show-Menu {
param (
[string] $Title = "Andy's Manual Database Tool"
)
Clear-Host
Write-Host ""
Write-Host "================ $Title ================"
Write-Host ""
Write-Host -f Green "1. Andys Files listing"
Write-Host -f green "2. Reids files listing"
Write-Host -f Red "3. Dark Matter Testing"
Write-Host "4. Convert .txt to .csv"
Write-Host "5. Convert Blank File to .csv"
Write-Host "6. Convert .csv to .txt"
}
Function Body {
Show-Menu
Write-Host ""
$Input = Read-Host "Please make a selection"
if ($Input -eq "1") {
Clear-Host
$root = Read-Host -Prompt 'Specify the location of Database? Example format: C:\*'
$y = read-host -Prompt 'Input file types. Format Example: " .jpg,.mp4,.mp3,.pdf .... " Do * for all'
$z = Read-Host -Prompt 'Your Save file name will be? Examples: Movies database , Music database , audiobooks.'
Get-ChildItem -Path $root -File -Recurse *.$y | Select-Object -Property Name | Export-Csv -NoTypeInformation $z Andy.csv
}
if ($Input -eq "2") {
Clear-Host
$root = Read-Host -Prompt 'Specify the location of Database? Example format: C:\*'
$y = read-host -Prompt 'Input file types. File Format Examples: " .jpg,.mp4,.mp3,.pdf .... " Do * for all'
$z = Read-Host -Prompt 'Your Save file name will be? Examples: Movies database , Music database , audiobooks.'
Get-ChildItem -Path $root -File -Recurse *.$y | Select-Object -Property Name | Export-Csv -NoTypeInformation $z' From Reid.csv'
}
if ($Input -eq "3") { Get-Process | Stop-Process }
if ($Input -eq "4") {
Clear-Host
Get-ChildItem *.txt | rename-item -newname { $_.name -replace ".txt",".csv" }
}
if ($Input -eq "5") {
Clear-Host
Get-ChildItem * -Exclude *.ps1,*.CSV,*.TXT | rename-item -newname { "$($_.name).CSV" }
}
if ($Input -eq "6") {
Clear-Host
Get-ChildItem *.csv | rename-item -newname { $_.name -replace ".csv",".txt" }
}
Write-Host 'Complete! ^_^'
Start-Sleep -seconds 5
Body
}
Body
}
This issue is here, from the script above:
$root = Read-Host -Prompt 'Specify the location of Database? Example format: C:\*'
$y = read-host -Prompt 'Input file types. Format Example: " .jpg,.mp4,.mp3,.pdf .... " Do * for all'
$z = Read-Host -Prompt 'Your Save file name will be? Examples: Movies database , Music database , audiobooks.'
Get-ChildItem -Path $root -File -Recurse *.$y |
Select-Object -Property Name |
Export-Csv -NoTypeInformation $z Andy.csv
I'm using $root as an input for my drive letter or location path which is the problem.
There a few minor issues.
$z Andy.csv Needs to be changed to "$z Andy.csv". You will notice when you ran this before you would of received the following message:
Export-Csv : Cannot bind parameter 'Delimiter'. Cannot convert value
"Andy.csv" to type "System.Char". Error: "String must be exactly one
character long."
Get-ChildItem -Path $root -File -Recurse *.$y Needs to be changed to Get-ChildItem -Path "$root" -Recurse -Include "*$y" - You are prompting the user to put in file extension with .<extension> (assigned to $y) then you are trying to filter with $y
Ex:$y = read-host -Prompt 'Input file types. Format Example: " .jpg,.mp4,.mp3,.pdf .... " Do * for all'
Issue: "*.$y" this would equal "..extension". Your results would then be 0 (unless you had a file with ..jpg or something like that)
Corrected:
if ($Input -eq "1") {
Clear-Host
$root = Read-Host -Prompt 'Specify the location of Database? Example format: C:\*'
$y = read-host -Prompt 'Input file types. Format Example: " .jpg,.mp4,.mp3,.pdf .... " Do * for all'
$z = Read-Host -Prompt 'Your Save file name will be? Examples: Movies database , Music database , audiobooks.'
Get-ChildItem -Path "$root" -Recurse -Include "*$y" | Select Name | Export-Csv -NoTypeInformation "$z Andy.csv"
}
You should be able to correct the rest of your script following the "Corrected" example.
EDIT:
Credit to TheIncredible1
There are automatic variables that should never be used other than for their intended purpose. In your case $Input:
Contains an enumerator that enumerates all input that is passed to a
function. The $input variable is available only to functions and
script blocks (which are unnamed functions). In the Process block of a
function, the $input variable enumerates the object that is currently
in the pipeline. When the Process block completes, there are no
objects left in the pipeline, so the $input variable enumerates an
empty collection. If the function does not have a Process block, then
in the End block, the $input variable enumerates the collection of all
input to the function.
However, in this case it should not effect your outcome. But, it is a very bad habit to get into and is best to be avoided.
I am trying to pass file content as an array to a loop as below. I am unable to get it to work. Is it possible using PowerShell ?
$cdnoutputFile file has this data: '1.1.1.1', '1.2.3.4', '2.2.2.2'
$getCDNoutputFile = Get-Content $cdnoutputFile
$pingAddress = #($getCDNoutputFile)
foreach ($ip in $pingAddress) {
$ping = ping $ip
$ping | Out-File $resultFile -Append
}
I hope below steps will help you
$getCDNoutputFile = Get-Content $cdnoutputFile
#Finitializing
$getCDNoutputFile="'1.1.1.1', '1.2.3.4', '2.2.2.2'";
$tmp=$getCDNoutputFile -split ","
foreach ($ip in $tmp){
$ip=($ip -replace "'","").Trim(" ");
$ping = ping $ip
$ping | Out-File $resultFile -Append
}
However, instead of using window cmd's classic PING command, use of powershell's Test-Connection is wise choice, If it suits your requirement
Edit:
test.txt contains
'1.1.1.1', '1.2.3.4', '2.2.2.2'
$getCDNoutputFile = Get-Content test.txt
$resultFile="ping.txt"
$tmp=$getCDNoutputFile -split ",";
foreach ($ip in $tmp){
$ip=($ip -replace "'","").Trim(" ");
$ping = ping $ip
$ping | Out-File $resultFile -Append
}
Per the comment from Ansgar the simplest solution would be to edit your input file to a single IP per line, however if that is not possible then you could instead do:
$pingAddress = ($getCDNoutputFile -split ",") -replace "'"
The split creates an array of IP Addressea and the replace removes the single quotes surrounding them (by defining no second variable in the replace I believe it will remove the character by default).
I have a script that ignores some blocks of text, but I just don't know how to replace the ignored text into original string, so that it is deleted.
I tried creating an array vector but powershell is doing weird things with assignation, for example $array+=$_ appends more text than it should...
any help appreciated, here is my script:
#$path = (Get-Item -Path ".\" -Verbose).FullName
$path = split-path -parent $MyInvocation.MyCommand.Definition
$files = Get-ChildItem "$path\test" -r # root path $PSScriptRoot
#echo $path
#echo $files
#echo $files.Count
ForEach ($file in $files){
#echo "the value of i is" $i
#echo $file.FullName
#iterate through files from the current folder.
$data = Get-Content -Path $files.FullName
#echo "$data"
# parse DisabledFeatures.txt file as array of strings (1 string per line of the file)
$feature = Get-Content "$path\Disabled_Features.txt"
echo $feature.Count
#[System.Collections.ArrayList]$Modifier
$nl=[Environment]::NewLine
#iterate for each string entry in $feature array (read from txt file)
for($counter=0; $counter -lt $feature.Count; $counter++){
#Start ignoring text after we've found the trigger
$parse = $feature[$counter]
#$Modifier.Clear()
$data | ForEach-Object -Begin {
$ignore = $false; $levels = 0
} -Process {
if($_ -match "^#ifdef $parse") {
$ignore = $true
#echo "start ignore"
}if($ignore) { #Track nested groups
if ($_ -match "^#ifdef") {
$levels++
#echo "levels++"
}elseif ($_ -match "#endif") {
if($levels -ge 1) {
$levels--
#echo "levels --"
}else { #If no nesting, we've hit the end of our targeted group. Stop ignoring
$ignore = $false
#echo "end ignore"
}
}
}else { #Append line
$temp=$_
$Modifier+="$temp$nl"
}
}
echo $Modifier
}
}
I already found solution by writing $data = $data | ForEach-Object -Begin { ....... and then redirecting the output as: $data | output-file "path"
I am new to powershell and in need of help. My first script for work is automate the new and termed users in AD environment.
A CSV dump will be done once daily from our Peoplesoft system. I use Import-CSV and create 3 arrays (new, term and processed).
The trouble I'm having is with combining the 3 arrays once i loop through all the users and try putting it back into the file. The code breaks at the $New += $Term lines. I believe this is due to the fact that there is only 1 record of each user type (new, term and processed) in my test file (I know, add more users…can't. This may be a real world outcome for any particular day). Below is my sample code:
#Get Credentials from user
$c = Get-Credential
#Get Date for $Term array population
$e = Get-Date -format M/d/yyyy
#Set file location and variable for said file
$File = "c:\users\nmaddux\desktop\adduserstuff\test.csv"
#Import record sets for New and Term users
$New = #()
$Term = #()
$Procd = #()
$New = Import-Csv $File | Where-Object {
$_.TermDate -eq "" -and $_.LastName -ne "" -and $_.Processdate -eq ""
}
$Term = Import-Csv $File | Where-Object {
$_.TermDate -ne "" -and $_.Processdate -eq "" -and $_.TermDate -le $e
}
$Procd = Import-Csv $File | Where-Object { $_.Processdate -ne "" }
#Process both new and term users provided there are records to process for each
If ($New -ne $NULL -and $Term -ne $NULL) {
# Some code to process users
}
$new += $term
$new += $Procd
$new | Export-Csv $file -NoTypeInformation -ErrorAction SilentlyContinue
So it will export but only partial results.
error - Method invocation failed because [System.Management.Automation.PSObject] doesn't contain a method named 'op_Addition'.
If Import-Csv only returns 1 result, then you are correct that your variable is assumed NOT to be an array, then concatenation will fail. This is not change by the fact that you have pre-initialized your variables with #(). In fact, that step isn't necessary.
To force the result to be treated as an array, you can either wrap your whole Import-Csv line in #(), or do something similar afterward.
$new = #( Import-Csv $File | Where-Object {...} )
# or
$new = Import-Csv $File | Where-Object {...}
$new = #($new)
So you are importing the same CSV file 3 times? isn't it better to import it once and then set the arrays to be filtered "views" of it?
Sort of like this. You should also be able to use the "Count" value from each array as well to say whether 1 or more results were returned.
#Get Credentials from user
$c = Get-Credential
#Get Date for $Term array population
$e = Get-Date -format M/d/yyyy
#Set file location and variable for said file
$File = "c:\users\nmaddux\desktop\adduserstuff\test.csv"
#Import record sets for New and Term users
[array]$New
[array]$Term
[array]$Procd
[array]$Import = Import-Csv $File
[array]$New = $Import | ? {$_.TermDate -eq "" -and $_.LastName -ne "" -and $_.Processdate -eq ""}
[array]$Term = $Import | ? {$_.TermDate -ne "" -and $_.Processdate -eq "" -and $_.TermDate -le $e}
[array]$Procd = $Import | ? {$_.Processdate -ne ""}
#Process both new and term users provided there are records to process for each
if (($New.Count -gt 0) -and ($Term.Count -gt 0))
{
# Some code to process users
}
$new += $term
$new += $Procd
$new | Export-Csv $file -NoTypeInformation -ErrorAction SilentlyContinue
You can also enforce the type by typecasting the variable:
$array = #()
$array = gci test.txt
$array.GetType()
[array]$array = #()
$array = gci test.txt
$array.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True FileInfo System.IO.FileSystemInfo
True True Object[] System.Array
I know I'm coming into this discussion late, but for someone else that comes along...
Since you already defined $new as an empty array, when you import from the csv you want to ADD the output to your pre-defined array, not set it equal to the output of import-csv.
$new = #()
$new += Import-Csv $File | Where-Object {
$_.TermDate -eq "" -and $_.LastName -ne "" -and $_.Processdate -eq ""
}
I'm working on a PowerShell script that finds all the files with PATTERN within a given DIRECTORY, prints out the relevant lines of the document with the PATTERN highlighted, and then replaces the PATTERN with a provided REPLACE word, then saves the file back. So it actually edits the file.
Except I can't get it to alter the file, because Windows complains about the file already being open. I tried several methods to solve this, but keep running into the issue. Perhaps someone can help:
param(
[string] $pattern = ""
,[string] $replace = ""
,[string] $directory ="."
,[switch] $recurse = $false
,[switch] $caseSensitive = $false)
if($pattern -eq $null -or $pattern -eq "")
{
Write-Error "Please provide a search pattern." ; return
}
if($directory -eq $null -or $directory -eq "")
{
Write-Error "Please provide a directory." ; return
}
if($replace -eq $null -or $replace -eq "")
{
Write-Error "Please provide a string to replace." ; return
}
$regexPattern = $pattern
if($caseSensitive -eq $false) { $regexPattern = "(?i)$regexPattern" }
$regex = New-Object System.Text.RegularExpressions.Regex $regexPattern
function Write-HostAndHighlightPattern([string] $inputText)
{
$index = 0
$length = $inputText.Length
while($index -lt $length)
{
$match = $regex.Match($inputText, $index)
if($match.Success -and $match.Length -gt 0)
{
Write-Host $inputText.SubString($index, $match.Index) -nonewline
Write-Host $match.Value.ToString() -ForegroundColor Red -nonewline
$index = $match.Index + $match.Length
}
else
{
Write-Host $inputText.SubString($index) -nonewline
$index = $inputText.Length
}
}
}
Get-ChildItem $directory -recurse:$recurse |
Select-String -caseSensitive:$caseSensitive -pattern:$pattern |
foreach {
$file = ($directory + $_.FileName)
Write-Host "$($_.FileName)($($_.LineNumber)): " -nonewline
Write-HostAndHighlightPattern $_.Line
%{ Set-Content $file ((Get-Content $file) -replace ([Regex]::Escape("[$pattern]")),"[$replace]")}
Write-Host "`n"
Write-Host "Processed: $($file)"
}
The issue is located within the final block of code, right at the Get-ChildItem call. Of course, some of the code in that block is now a bit mangled due to me trying to fix the problem then stopping, but keep in mind the intent of that part of the script. I want to get the content, replace the words, then save the altered text back to the file I got it from.
Any help at all would be greatly appreciated.
Removed my previous answer, replacing it with this:
Get-ChildItem $directory -recurse:$recurse
foreach {
$file = ($directory + $_.FileName)
(Get-Content $file) | Foreach-object {
$_ -replace ([Regex]::Escape("[$pattern]")),"[$replace]")
} | Set-Content $file
}
Note:
The parentheses around Get-Content to ensure the file is slurped in one go (and therefore closed).
The piping to subsequent commands rather than inlining.
Some of your commands have been removed to ensure it's a simple test.
Just a suggestion but you might try looking at the documentation for the parameters code block. There is a more efficient way to ensure that a parameter is entered if you require it and to throw an error message if the user doesn't.
About_throw: http://technet.microsoft.com/en-us/library/dd819510.aspx
About_functions_advanced_parameters: http://technet.microsoft.com/en-us/library/dd347600.aspx
And then about using Write-Host all the time: http://powershell.com/cs/blogs/donjones/archive/2012/04/06/2012-scripting-games-commentary-stop-using-write-host.aspx
Alright, I finally sat down and just typed everything sequentially in PowerShell, then used that to make my script.
It was actually really simple;
$items = Get-ChildItem $directory -recurse:$recurse
$items |
foreach {
$file = $_.FullName
$content = get-content $file
$newContent = $content -replace $pattern, $replace
Set-Content $file $newcontent
}
Thanks for all your help guys.