I am writing a PowerShell script to gather general information on our servers. I wrote the script so that it outputs to a file called output.txt via PowerShells Start-Transcript cmdlet. Output works fine. However I just want the output in the file and not displayed on the console.
I have been looking and attempting to see if Start-Transcription can suppress the console output but I have not found anything.
This is a very cut down version of the code I am using-
Start-Transcript -path "Path\To\Output\File.txt"
$servers = Get-Content -path "Path\To\Servers\List\file.txt"
foreach ($server in $servers)
{
net view
net use
net session
}
Stop-Transcript
It all outputs to the file correctly but I just would like it to NOT display the script/command results in the console. If that is possible.
Would this work?
$FilePath = 'Path\To\Output\File.txt'
net view | Out-File -FilePath $FilePath
net use | Out-File -FilePath $FilePath -NoClobber -Append
net session | Out-File -FilePath $FilePath -NoClobber -Append
Or bundle it:
Invoke-Command {net view ; net use ; net session} | Out-File -FilePath $FilePath -NoClobber -Append
EDIT based on comment (but written freely from memory on an iphone so maybe minor mistakes):
To run this remotely against a list of servers you first enable Powershell remoting on the servers, many ways to do it and here is one to run in a local powershell session on each server (Runas Admin):
winrm quickconfig
Then, assuming they all have the same login, you can:
$Cred = Get-Credential
$Servers = ’server1.example.com’,’server2.example.com’
Invoke-Command -ComputerNames $Servers -Credential $Cred -ScriptBlock {
Do stuff
Do some other stuff
} | Out-File -FilePath $FilePath -NoClobber -Append
Results are returned as an array so if you want to separate the output per server you could try:
$a = Invoke-Command [...]etc but skip the |Out-File
then do some loop which in essence does this part, giving you the manual way here:
$a[0] | Out-File -FilePath $FilePath1 -NoClobber -Append #result from first computer
$a[1] | Out-File -FilePath $FilePath2 -NoClobber -Append #result from second computer
...
and an example loop:
$a | Foreach-Object {$_ | Out-File -FilePath $Path -Append -NoClobber}
And to read the servernames from a text file, one servername per line:
$Servers = Get-Content -Path ’C:\temp\example.txt’
Invoke-Command -ComputerName $Servers [...]etc
Related
Im trying to copy and install certificates on remote computers, but a i need insert a pause "press enter to continue.." at the end of each server on the loop.
$servers = Get-Content "D:\scripts\InstallCertRemote\servers.txt"
$LocalPath = "D:\Temp\*.*"
$RemotePath = "D$\Temp\certificates"
$logfile = "D:\scripts\InstallCertRemote\logfile.txt"
ForEach ($server in $servers)
{Get-Date | out-file $logfile -Append
Write-host Copying files on $server
(copy-item -Path $LocalPath -Destination "\\$server\$RemotePath" -Verbose 4>&1 | out-file $logfile -Append)
Start-Sleep 2
Write-host Installing certificate on $server
(Invoke-Command -ComputerName "$server" -ScriptBlock {Import-Certificate -FilePath "S:\temp\certificates\certificate.cer" -CertStoreLocation Cert:\LocalMachine\ROOT} -Verbose 4>&1 | out-file $logfile -Append)
}
How can i do it?
Thanks,
Placing this here since it is too long for the comment section.
Why are you not using ADDS/GPO/SCEP to push certs to clients
Distribute Certificates to Client Computers by Using Group Policy -
vs scripting, this or why is this
MSDocs - Installing security certificates
not an option for you?
So far I have created a PowerShell script to find the specific files from multiple servers and dump the output to excel file.
For some reason my script only dumps the output for 1 server (last one to the list) out of 50. Not sure what I'm missing.
$server = get-content "C:\temp\servers.txt"
Foreach ($srv in $server)
{
Get-ChildItem -Path "\\$srv\d$\temp\" -include "java_pid*" -Recurse -ErrorAction silentlycontinue | export-csv c:\temp\results.csv
}
When run the script it will go thru all the servers and dump the export to excel file.
Use the -Append tag this will append each of the server results pipeline into one long results.csv. Right now you are overwriting the output csv for each server.
$server = get-content "C:\temp\servers.txt" Foreach ($srv in $server) { Get-ChildItem -Path "\$srv\d$\temp\" -include "java_pid*" -Recurse -ErrorAction silentlycontinue | export-csv c:\temp\results.csv -Append}
When I search this site, others have suggested using options like -NoNewWindow However, that doesnt seem to help.
I am writing a script that installs SCCM. It is quite a long install (about 5 min) and even though I have the -Wait, it literally continues on throughout the remainder of the script.
Start-Process -FilePath C:\temp\SCCM_Client\ccmsetup.exe -ArgumentList SMSSITECODE=PCM -Wait
Write-Host "Verify SCCM client install after reboot"`r`n -ForegroundColor Green
It runs the ccmsetup.exe then after about 5 seconds or so, it continues on to the next line. I check task manager and ccmsetup.exe is CLEARLY still running.
So you guys think Im having a problem because this is an installer and not a program? (this command works just fine if I Start-process notepad.exe; it wont continue on until I close notepad) That's the only thing I can think of that's different
Thanks for any help!
I had this problem, ccmsetup.exe spawns another process which does the work. So it's behaving as expected because the ccmsetup.exe spawned by powershell has finished.
To get around this, my solution was to monitor the ccmsetup logs for an exit code.
Something like below.
$count = 1
$LogFilePath = 'C:\Windows\ccmsetup\Logs\ccmsetup.log'
do
{
Write-Output "Uninstalling Software Center - attempt $count"
Start-Process -FilePath C:\temp\SCCM_Client\ccmsetup.exe -ArgumentList SMSSITECODE=PCM
$count++
Start-Sleep 30
while ((Get-Content -Path $LogFilePath -Tail 1 | Select-String -Pattern "CcmSetup is exiting with return code" -SimpleMatch) -eq $null)
{
#Check every 10 seconds for an exit code
Start-Sleep 10
}
} until((Get-Content $LogFilePath -Tail 1 -Wait | Select-String -pattern "CcmSetup is exiting with return code 0" -SimpleMatch -Quiet) -or $count -gt 3)
I'm not in work at the moment, so don't have access to the actual portion of code - I'll try to update this tomorrow with the final version I used.
The Start-sleep 30 was required to prevent it checking the log prematurely and using an old exit code.
My solution to this particular problem was to use SCCM to build a batch file that actually works and runs separately from SCCM. It's an utterly insane solution.. but welcome to coding, I guess.
Write-Output "MsiExec.exe /x{5974413A-8D95-4D64-B9EE-40DF28186445} /qn" | Out-File -Encoding ASCII -FilePath mcafee-removal.bat
Write-Output "MsiExec.exe /x{377DA1C7-79DE-4102-8DB7-5C2296A3E960} /qn" | Out-File -Encoding ASCII -FilePath mcafee-removal.bat -Append
Write-Output "MsiExec.exe /x{820D7600-089E-486B-860F-279B8119A893} /qn" | Out-File -Encoding ASCII -FilePath mcafee-removal.bat -Append
Write-Output "MsiExec.exe /x{B16DE18D-4D5D-45F8-92BD-8DC17225AFD8} /qn" | Out-File -Encoding ASCII -FilePath mcafee-removal.bat -Append
Write-Output """%programfiles%\McAfee\Agent\x86\frminst.exe"" /remove=agent /silent" | Out-File -Encoding ASCII -FilePath mcafee-removal.bat -Append
Start-Process -FilePath "cmd.exe" -ArgumentList '/c .\mcafee-removal.bat'
The batch file behaves exactly the way you'd expect it to. SCCM's weird C++ implementation of powershell parsing ... yeah, not so much.
Hope this helps someone someday.
On a remote server there is a .BAT file which uses a .properties file to run.
I am able to run the .BAT file calling the .properties file, but in that .properties file last line is:
exportQuery1=SELECT * FROM CI_INFOOBJECTS where SI_ID='123456'.
I am modifying that line/SI_ID value manually which actually increasing my effort.
I have tried a few options but am not able to provide the value/entire line from the local powershell commandline which will be written in the .properties file.
So I have to modify the .ps1 every time. I want to pass the entry with the local powershell command as a variable.
Deleting the old line:
Invoke-Command -computername $ServerName -Credential $Cred -ErrorAction stop -ScriptBlock {Set-Content -Path D:\Script\TestFile.txt -Value (get-content -Path D:\Script\TestFile.txt | Select-String -Pattern 'SI_ID' -NotMatch)}
Creating the New line at the end of the file:
Invoke-Command -computername $ServerName -Credential $Cred -ErrorAction stop -ScriptBlock {add-content D:\Script\TestFile.txt "exportQuery1=SELECT * FROM CI_INFOOBJECTS where SI_ID='abcdef'"}
Please help to pass the SI_ID/entire line from the command while executing the script.
Why not use a simple parameter and the using statement in a single invoke call?
param($SI_ID)
$SB = {
Set-Content -Path D:\Script\TestFile.txt -Value (get-content -Path D:\Script\TestFile.txt | Select-String -Pattern 'SI_ID' -NotMatch)
add-content D:\Script\TestFile.txt "exportQuery1=SELECT * FROM CI_INFOOBJECTS where SI_ID='$using:SI_ID'"
}
Invoke-Command -computername $ServerName -Credential $Cred -ErrorAction stop -ScriptBlock $SB
then just .\myscript -SI_ID "abcd"
I'm trying to run a command which accepts a list of names. It should go through each member of the list and then output it to a text file in a specific location, and the name of that text file will be the member name from the list. Then the script continues to the next member run the command on it, and then write the output to a text file whose name will be the 2nd member in the list.
I'm sure a loop is involved, and perhaps a temporary variable which I have no idea how to declare :(
Invoke-Command -ComputerName (Get-Content "C:\ServerList.txt") -ScriptBlock {
Servermanagercmd.exe -query roles.xml
} -credential baloon\yellow | Out-File C:\OutputF.txt
Pull out the Get-Content of the serverlist file so the server name values are available down the pipeline:
Get-Content c:\serverlist.txt | Where {$_} |
Foreach { Invoke-Command -ComputerName $_ -Scriptblock {...} -Credential baloon\yellow |
Out-File "$_.txt" }
Note that the Where {$_} is to weed out any empty lines in the file.
Shall I assume this issue is that the data that is being output has no context since you wont know what system it is from?
$outputfile = C:\OutputF.txt
Set-Content -Path $outputfile -Value ""
ForEach($server in (Get-Content "C:\ServerList.txt")){
Add-Content -Path $outputfile -Value "Server: $server"
Invoke-Command -ComputerName $server -ScriptBlock {Servermanagercmd.exe -query roles.xml} -credential baloon\yellow |
Add-Content -Path $outputfile
}
Wipe the file to start new (remove this if you dont want to erase the file.). For each server in your list add the server name on its own line in the file and then run the Invoke-Command also sending its output to file.
This will might be inefficient depending on the number of server you are checking. At that point I would consider using jobs.
Update
After reading Keith Hills answer I realize that I misread your question. My logic would output all to one file with the server name separating the contents. You actually wanted separate files.