Save powershell script after entering details for read-host - powershell

Example:
$nameofpath = read-host "enter path"
get-services | export-csv "$nameofpath"
I want a script so after entering a path such as c:\files\test.txt in the example above, it will save a script with:
get-services | export-csv "c:\files\test.txt"
... so I could go to that file click it and it will run.
At the moment I have an draft script like this but if I know how to do the first example I should hopefully be able to do the same for that

You'd either need to change the script that you're running, or query some other text file. If there is anything in the text file, use that; otherwise, prompt for the value. Here's an example of how you could change the script you're running using the $PSCommandPath (it's an automatic variable that contains the full path and file name of the script that is being run) variable:
$Foo = $null
#If $Foo is $null prompt for value then write that value to the script.
if($Foo -eq $null){
$Foo = Read-Host "Foo"
#Need to becarful not to match this line
$NewScript = Get-Content $PSCommandPath | ForEach-Object {$_ -replace '^\$Foo = \$null$',"`$Foo = '$Foo'"}
$NewScript | Out-File $PSCommandPath -Force
}
Write-Host "Foo $Foo"
Hope this helps.

This looks amateur but works as expected
$path = [Microsoft.VisualBasic.Interaction]::InputBox("Enter path")
[System.Reflection.Assembly]::LoadWithPartialName('Microsoft.VisualBasic') | Out-Null
get-service | export-csv -path $path\services.csv # original command
$Command="get-service | export-csv -path $path\services.csv" # same copy here to save
$command |Out-File "D:\exportservice.ps1" # where you want the file to be saved to run later

Related

I need my script to accept input from a file rather than read-host

I have a ps script which will ask for a number, then search for that number in a location with 1000s of files, copy those file names having those number and then output it to a file. That number is also saved in a txt file in a different location, from which I manually copy and insert into this script. Is it possible to make the script read from the 2nd line onwards of the file containing the number, then search for that number within files, like it is doing now?
This is the code I am using:-
$Path = "D:\Projects\MSMQ Journal Messages\PurchaseManagementPO"
$Text = Read-Host -Prompt "PO Number"
$PathArray = #()
$Results = "D:\Chayan\POmiss\miss.txt"
# This code snippet gets all the files in $Path that end in ".xml".
Get-ChildItem $Path -Filter "*.xml" |
Where-Object { $_.Attributes -ne "Directory"} |
ForEach-Object {
If (Get-Content $_.FullName | Select-String -Pattern $Text)
{
$PathArray += $_.FullName
$PathArray += $_.FullName
}
}
Write-Host "Contents of ArrayPath:"
$PathArray | % {$_} | Out-File "D:\Chayan\POmiss\miss.txt" -Append
That PO Number comes from a file, which is generated through a different script, and gets saved like below:-
ponumMaster
908859
280973
I manually put these number in the read-host to do the search and save file name. Is there a way powershell can copy these numbers from this file and do the task?
You should be able to use -skip to move past the first line
The example below would skip the first line and give the results after that
get-content C:\_lab\test.txt | select -skip 1
This example would skip the first line and only give the results from the second line
get-content C:\_lab\test.txt | select -first 1 -skip 1
For your script, you should just need to do the following:
$Text = get-content C:\_lab\test.txt | select -skip 1
#we clear this variable so it can be run multiple times in the same session
clear-variable final -ErrorAction Ignore
#grab txt file content and split into an array
[array]$txt=(get-content "D:\Chayan\POmiss\miss.txt") -split " "
#take out the blanks and assign to new variable called final (we clear this above so it can be run multiple times in the same session)
foreach($line in $txt){
if($line.replace(" ","")){
[array]$final+=$line
}
}
#run script, calling the variable $text in place of the numbers
foreach($text in $final){
(your normal script here)
}

How to pull a sentence from a log file on multiple remote computers

I am needing to pull a specific sentence from a log file on multiple remote computers. I have all of the computer names already but I do not know how to go about pulling contents of a file from them and copying all of it to a file so that I can reference the sentence from each computer with its machine name. Basically each machine has a specific number unique to itself that we need.
Before explaining, I assume powershell is the tool to use for this.
There are about 1800 machines and I have a variable for all of those. Then I assume I have to make a loop of some kind that runs on each of those machines.
the loop would pull the text from that file that I need and save it all to a file. I am basically pretty new in my Net Admin position with not a lot of PowerShell experience and I wondered if anyone could help.
$computers = ***list of computers***
$computers | ForEachObject{
Add-Content -Path C:\Users\Public\Activant\Eagle\3log.log -Value "Terminal information for ***need the info that is here***"
}
Get-Content -Path .\TERMINAL NUMBERS.txt
this seems to do what you want. [grin] it builds a scriptblock that does the work, hands that off to Invoke-Command with a list of systems to run it on, gathers the results, creates a list of $Non-Responders, removes unwanted properties added by the I-C cmdlet, and finally shows the two collections.
#requires -RunAsAdministrator
# fake reading in a text file
# in real life, use Get-Content
$ComputerNameList = #'
LocalHost
10.0.0.1
127.0.0.1
BetterNotBeThere
'# -split [System.Environment]::NewLine
$IC_ScriptBlock = {
$TargetFileName = 'C:\Temp\Grouping-Strings-List_2019-07-31.log'
# the " \b\w+\b \b\w+\b " is two words delimited by spaces
# so this will find any line that has two words between the listed phrases
$LinePattern = '^Acid Drum \b\w+\b \b\w+\b Psychedelic$'
# the next line is a no-match patern for testing
#$LinePattern = '^Acid Drum \b\w+\b$'
$Line = (Get-Content -LiteralPath $TargetFileName |
Select-String -Pattern $LinePattern).Line
if ([string]::IsNullOrEmpty($Line))
{
$Line = '__Not Found__'
}
[PSCustomObject]#{
ComputerName = $env:COMPUTERNAME
LineText = $Line
}
}
$IC_Params = #{
ComputerName = $ComputerNameList
ScriptBlock = $IC_ScriptBlock
# comment out the next line to see any errors in the I-C call
ErrorAction = 'SilentlyContinue'
}
$Responders = Invoke-Command #IC_Params
$Non_Responders = $ComputerNameList.Where({$_ -notin $Responders.PSComputerName})
# the next line removes unwated properties added by "Invoke-Command"
$Responders = $Responders |
Select-Object -Property * -ExcludeProperty PSComputerName, PSShowComputerName, RunspaceId
$Responders
'=' * 40
$Non_Responders
output ...
ComputerName LineText
------------ --------
[MySysName] Acid Drum Instrumental Live Psychedelic
[MySysName] Acid Drum Instrumental Live Psychedelic
========================================
10.0.0.1
BetterNotBeThere
if needed, you can create a single collection from the two above fairly directly. [grin]
I think what you are trying to do is to READ the line from a file all computers in your list should have, located at C:\Users\Public\Activant\Eagle\3log.log
In that case, something like below should work:
# use UNC naming for the remote file path
$inputFile = 'C$\Users\Public\Activant\Eagle\3log.log' # I'm guessing this is the file you want to read
$outputFile = 'C:\TERMINAL NUMBERS.txt'
$computers = ***list of computers*** # the array of computer names
$result = $computers | ForEach-Object {
# test if the computer is online
if (Test-Connection -ComputerName $_ -Count 1 -Quiet) {
# create the full UNC path by prepending the common file path with the computer name
$file = '\\{0}\{1}' -f $_, $inputFile
# test if the file can be found or not
if (Test-Path -LiteralPath $file -PathType Leaf) {
# using non regex string search
$line = (Select-String -LiteralPath $file -Pattern "whatever you're looking for" -SimpleMatch).Line
if (!$line) {
# the file is there, but the pattern was not found
$line = "Pattern not found"
}
}
else {
$line = "File '$inputFile' not found."
}
}
else {
$line = 'Computer is Off-Line'
}
# Finally, add this info to your text file
Add-Content -Path $outputFile -Value "$_ --> $line"
# And emit an object for the $result collection. This will display nicely on screen,
# but also allow for the creation of a CSV file which might be better as output.
[PsCustomObject]#{
'Computer' = $_
'LogInfo' = $line
}
}
Afterwards you can read the output text file or (better I think) use the $result collection for output:
On screen:
$result | Format-Table -AutoSize
To CSV file
$result | Export-Csv -Path 'C:\TERMINAL NUMBERS.csv' -NoTypeInformation -Force

How can I write a script that will read other scripts and record their processes?

I have a folder of scripts that are being used for my company, and I need to know what each script does. I am trying to write a script in power shell that will record what each script does into a csv file.
I am a beginner in Powershell and am still learning so I apologize if I am being unclear.
I know that each of these scripts basic function is to map drives to a users computer, but there are too many to go through manually, any advice would be appreciated!
EDIT: Most of them are bat with a couple of vbs too. I want to record what drives are being mapped.
EDIT 2: I have now written my own script that looks like this :
Set-location z:\
get-Childitem "z:\Test"|
Foreach-object{
$filename = $_.Fullname
Get-content $filename|
foreach-object {
if ($_ -match "echo off") {
Write-output "$($filename): $_" | select-object $_ $filename
| export-csv "test.csv" -notypeinformation
}
}
}
I am having trouble exporting the data into a csv file as the error "A positional parameter cannot be found that accepts argument 'z:\Test\Test1.bat'"
The easiest way will be string parsing: look for the commands that map the drives. That's net use for bat files, or MapNetworkDrive in VBS. So look for those lines.
This will look through all the files in a folder and output the filename and the content of the line wherever it finds those lines:
Get-ChildItem "C:\Scripts" |
Foreach-Object {
$filename = $_.FullName
Get-Content $filename |
Foreach-Object {
if ($_ -match "net use" -or $_ -match "MapNetworkDrive") {
Write-Output "$($filename): $_"
}
}
}
That will not likely be exactly what you need, but it should get you started.

Pipe all Write-Output to the same Out-File in PowerShell

As the title suggests, how do you make it so all of the Write-Outputs - no matter where they appear - automatically append to your defined log file? That way the script will be nicer to read and it removes a tiny bit of work!
Little example below, id like to see none of the "| Out-File" if possible, yet have them still output to that file!
$Author = 'Max'
$Time = Get-Date -Format "HH:mm:ss.fff"
$Title = "Illegal Software Removal"
$LogName = "Illegal_Remove_$($env:COMPUTERNAME).log"
$Log = "C:\Windows\Logs\Software" + "\" + $LogName
$RemoteLog = "\\Server\Adobe Illegal Software Removal"
Set-PSBreakpoint -Variable Time -Mode Read -Action { $global:Time = Get-Date -format "HH:mm:ss.fff" } | Out-Null
If((Test-Path $Log) -eq $False){ New-Item $Log -ItemType "File" -Force | Out-Null }
Else { $Null }
"[$Time][Startup] $Title : Created by $Author" | Out-File $Log -Append
"[$Time][Startup] Configuring initial variables required before run..." | Out-File $Log -Append
EDIT: This needs to work on PS v2.0, I don't want the output to appear on screen at all only in the log. So I have the same functionality, but the script would look like so...
"[$Time][Startup] $Title : Created by $Author"
"[$Time][Startup] Configuring initial variables required before run..."
You have two options, one is to do the redirection at the point the script is invoked e.g.:
PowerShell.exe -Command "& {c:\myscript.ps1}" > c:\myscript.log
Or you can use the Start-Transcript command to record everything (except exe output) the shell sees. After the script is done call Stop-Transcript.

Powershell Pass "Press any key to continue" from another script

I'm writing a powershell script to automate some updates.
For this purpose I need to execute another script and save the output into a variable.
Afterwards I can cut the things that I need off and save them into other variables.
These things theoreticly work but the other script which I'm executing stops the process,
beause it need any key to continue at the end.
Does somebody know how I can pass this?
The scripts stops after:
$list = .\list.cmd
Kind regards :)
Thats a part of the script:
Write-Host "Importing..."
cd "$path"
$list = .\list.cmd
Write-Host "Searching for the certificate file"
$CertificateFile = $list | where {$_ -match "Certificate File:"}
$CertificateFile = $CertificateFile.Substring(18)
Write-Host "I'm trying to find the Password File:"
$PasswordFile = $PasswordFile = $list | where {$_ -match "Password File:"}
$PasswordFile.Substring(15)
Write-Host "Searching for the password file"
$Enddate = $list | where {$_ -match "Validity NotAfter:"}
$Enddate = $Enddate.Substring(19)
Here is how you send a keystroke. As for timing, it needs to occur when the paused app is in the foreground 'active' window.
add-type -AssemblyName System.Windows.Forms
[System.Windows.Forms.SendKeys]::SendWait("A")