Powershell script copy and install certificate on remote computer - powershell

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?

Related

Powershell script searching files on domain

Very new to powershell and AD, so apologies if this post has an obvious answer. I have done some research and I am still not finding the answers I am looking for. My script is below for reference.
I have created a simple powershell script that will run on an admin vm i have setup on my domain. I have a separate SQL vm running a backup script that consume a lot of storage over time. I am trying to run this very simple script. My question is, do I need to modify this script in order to store it on my admin vm but have it run on my sql vm? Or can i leave the path as is and just set up in AD task scheduler. I have tried targeting the FQDN and the IP, but it doesn't seem to be working either way.
$backups_file = 'E:\blahBlahBla\SQL\Backups' or
$backups_file = '<IP_ADDRESS>\E:\blahBlahBla\SQL\Backups' or
$backups_file = '<FQDN>E:\blahBlahBla\SQL\Backups'
$backup_file_exist = (Test-Path -Path $backups_file)
if ($backup_file_exist){
# Verifies the folder exists
Write-Output -InputObject "This folder exists"
# returns all the files in the folder.
Get-ChildItem -Path $backups_file
# Deletes all files in the folder that are older that 7 days.
Get-ChildItem -Path $backups_file -Recurse | Where-Object {($_.LastWriteTime -lt (Get-
Date).AddDays(-7))} | Remove-Item
}
else
{
Write-Output -InputObject "Unable to access this directory."
}
Thanks.
well all your $backups_file solutions seems wrong to me.
If you want excess a directory on a Remote system, it has to be at least a fileshare or a administrative share like \\computer\e$\folder\folder\
But why using file shares or something like that when you just simple can connect to a Powershell Session on the Remote Host? here is a example.:
$mySQLServer = "Server1.domain.name", "server2.domain.name"
$backupFolder = "E:\blahBlahBla\SQL\Backups"
foreach ($server in $mySQLServer)
{
$session = New-PSSession -ComputerName $server #maybe -cred if needed
Invoke-Command -Session $session -ArgumentList $backupFolder -ScriptBlock {
param(
$directoy
)
if ($backup_file_exist)
{
# Verifies the folder exists
Write-Output -InputObject "This folder exists"
# returns all the files in the folder.
Get-ChildItem -Path $directoy
# Deletes all files in the folder that are older that 7 days.
Get-ChildItem -Path $directoy -Recurse | Where-Object { ($_.LastWriteTime -lt (Get-Date).AddDays(-7))
} | Remove-Item
}
}
Remove-PSSession
}
Good Luck!

Invoke-Command doesn't return to local machine but software is installed

The tl;dr: I'm puzzled as to why my script isn't returning back to the deployment machine. Does anyone have an idea why?
I was provided an EXE and a couple arguments to install some software. I'm using PowerShell's Start-Process to run it. The deployment machine is Win Server 2012 domain controller, logged in and being run as domain admin. The test machines are two Windows 10 Pro domained machines. All three have PS 5.1.
Being a silent install, there is no user interaction required. If I run the exact command locally, via RDP, or in a pssession, with just c:\Software.exe /silent /arg2removed, it installs and returns as expected.
The script runs fine up to a point. Nothing happens after Start-Process inside Invoke-Command 's -ScriptBlock. In a separate PowerShell window, I can use Enter-PSSession for each of the two client machines, and Get-Service and Get-Process both show the software's service and background processes, respectively. I can Ctrl+c on the deployment machine and get back to a prompt. No errors are reported at any time.
Here's the Start-Process chunk. I've read the help and it doesn't sound like I'm missing anything that would allow the ScriptBlock to finish. If I prepend Start-Process with Write-Host (like we all do), it echoes the command that would run and I get back to a command prompt on the deployment machine.
# Start the installer.
Start-Process `
-FilePath "C:\${using:SrcExe}" `
-ArgumentList "/SILENT", "/arg2removed" `
-WorkingDirectory C:\ `
-Wait `
-Verbose `
-ErrorAction SilentlyContinue `
-ErrorVariable InstallErrors
Here's most of the script. The only items before Invoke-Command are where I set up $ComputersToInstallOn, enter the credentials (yes I'm sure they're correct), and supply the path to the EXE.
Invoke-Command `
-ComputerName $ComputersToInstallOn `
-Credential $Creds `
-Verbose `
-ErrorAction SilentlyContinue `
-ErrorVariable InvokeCommErrors `
-ScriptBlock {
# Get and print the destination machine's hostname
$ThisMachine = Get-Content Env:\COMPUTERNAME ; $ThisMachine
# Print the current date and time
Get-Date
# Check if Sentinel processes are running. If not, assume it's not installed.
$S1Procs = get-process sentinel*
if([string]::IsNullOrEmpty($S1Procs)) {
# Sentinel isn't installed. Continue.
# Map a drive letter to $SrcFolder. Not theoretically necessary but Start-Process complains when copying with the UNC path directly.
New-PSDrive `
-Name S `
-PSProvider FileSystem `
-Credential ${using:Creds} `
-Root ${using:SrcFolder} `
-verbose
# List remote folder
Get-ChildItem S:\
# Copy the $SrcExe to C:\
Copy-Item `
-Path "S:\${using:SrcExe}" `
-Destination C:\ `
-Verbose `
-ErrorAction Stop `
-ErrorVariable CopyErrors
# Unmount drive
Remove-PSDrive S -verbose
# Verify EXE exists locally
Get-ChildItem -Path C:\${using:SrcExe}
# If there were copy errors, abort.
if ($CopyErrors) {
Write-Host "There was an error copying '${using:SrcExe}' to $ThisMachine. Aborting."
exit 1 } else {
# All good so far. Continue to install.
Write-Host "$(Get-Date -UFormat '%Y%m%d %H:%M:%S') : Starting install on ${ThisMachine}. You may need to Ctrl+C to return to the local machine. Check processes on each machine though."
# Start the installer.
Start-Process `
-FilePath "C:\${using:SrcExe}" `
-ArgumentList "/SILENT", "/arg2removed" `
-WorkingDirectory C:\ `
-Wait `
-Verbose `
-ErrorAction SilentlyContinue `
-ErrorVariable InstallErrors
# ScriptBlock doesn't seem to make it to anything after Start-Process.
# Remove the EXE.
Remove-Item "C:\${using:SrcExe}" -Verbose -ErrorAction SilentlyContinue
exit 0
# Get-Process -Name Sentinel*
# echo "Sleeping. Now would be the time to abort."
# Start-Sleep 15
}
} else {
Write-Host "Sentinel appears to be installed and running."
$S1Procs
Get-Service -Name Sentinel* | Where-Object { $_.Status -match "Running" }
exit 0
}
}
if($InvokeCommErrors){
Write-Host "There were some errors."
}
EDIT: Added some requested info.

Powershell Trasnscript - Output to a file and NOT display in console

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

Run Registry File Remotely with PowerShell

I'm using the following script to run test.reg on multiple remote systems:
$computers = Get-Content computers.txt
Invoke-Command -ComputerName $computers -ScriptBlock {
regedit /i /s "\\SERVER\C$\RegistryFiles\test.reg"
}
The script doesn't error, but the registry entry doesn't import on any of the systems.
I know test.reg file is a valid registry file because I copied it over, ran it manually, and the registry key imports. I also made sure PowerShell Remoting is enabled on the remote computers.
Any ideas why the registry key isn't importing?
I found the best way not to mess with issues related to server authentication and cut down on complexity just to pass Reg file as parameter to function.
$regFile = #"
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\Tcpip\Parameters]
"MaxUserPort"=dword:00005000
"TcpTimedWaitDelay"=dword:0000001e
"#
Invoke-Command -ComputerName computerName -ScriptBlock {param($regFile) $regFile | out-file $env:temp\a.reg;
reg.exe import $env:temp\a.reg } -ArgumentList $regFile
I posted on some PowerShell forums and finally got this working.
I had to 1) move the $newfile variable inside the loop and 2) comment out the $ in the path stored in the $newfile variable.
For reference, the final script looks like this if anyone wants to use it:
$servers = Get-Content servers.txt
$HostedRegFile = "C:\Scripts\RegistryFiles\test.reg"
foreach ($server in $servers)
{
$newfile = "\\$server\c`$\Downloads\RegistryFiles\test.reg"
New-Item -ErrorAction SilentlyContinue -ItemType directory -Path \\$server\C$\Downloads\RegistryFiles
Copy-Item $HostedRegFile -Destination $newfile
Invoke-Command -ComputerName $server -ScriptBlock {
Start-Process -filepath "C:\windows\regedit.exe" -argumentlist "/s C:\Downloads\RegistryFiles\test.reg"
}
}

PowerShell Command to Copy File on Remote Machine

I have a requirement to copy file from local machine to remote machine using PowerShell. I can copy the file to remote computer using following command:
copy-item -Path d:\Shared\test.txt -Destination \\server1\Shared
the above command uses network share path to copy the file. I don't want to use network share option as the folder will not be shared on the remote machine. I tried following commands but not working.
copy-item -Path d:\Shared\test.txt -Destination \\server1\c$\Shared
Invoke-Command -ComputerName \\server -ScriptBlock {
copy-item -Path D:\Shared\test.txt -Destination C:\Shared
}
Please let me know how to make it working without using UNC path. I have full permissions on that folder on the remote machine.
Quickest way I found to this, since the account being used is Administrator, is to do the following:
New-PSDrive -Name X -PSProvider FileSystem -Root \\MyRemoteServer\c$\My\Folder\Somewhere\
cd X:\
cp ~\Desktop\MyFile.txt .\
## Important, need to exit out of X:\ for unmouting share
cd c:\
Remove-PSDrive X
Works every time.
You must have a shared folder to be able to copy files from one host to another, either on the remote host if you want to push the file:
Copy-Item -Path D:\folder\test.txt -Destination \\server1\remoteshare\
or on the local host if you want to pull the file:
Invoke-Command -ComputerName server1 -ScriptBlock {
Copy-Item -Path \\localcomputer\localshare\test.txt -Destination C:\Shared\
}
Administrative shares (\\server1\c$) can only be used if your account has admin privileges on that particular computer.
If there is not an accessible share, you'll have to make the file content itself an argument to the script:
Invoke-Command -ComputerName \\server -ScriptBlock {
$args[0] | Set-Content C:\Shared\test.txt
} -ArgumentList (Get-Content D:\Shared\test.txt -Raw)
Powershell 5 (Windows Server 2016)
Also downloadable for earlier versions of Windows. -ToSession can also be used.
$b = New-PSSession B
Copy-Item -FromSession $b C:\Programs\temp\test.txt -Destination C:\Programs\temp\test.txt
Earlier versions of PowerShell
Does not require anything special, these hidden shares exist on all machines.
Copy-Item -Path \\serverb\c$\programs\temp\test.txt -Destination \\servera\c$\programs\temp\test.txt
Invoke-Command -ComputerName compname -Credential $cred -ScriptBlock { Get-Content C:\myfolder\result.txt } >>res.txt
Note the C:\myfolder\result.txt is on the remote computer
Here's a script that worked for me for small files. Run as admin.
#pre 5.0 powershell copy-item to remote computer
Write-Host "Remote copy a file"
$servers = #("server01.dot.com", "server02.dot.com")
foreach($server in $servers) {
$username = 'USERNAME'
$password = 'PASSWORD'
$pw = ConvertTo-SecureString $password -AsPlainText -Force
$cred = New-Object Management.Automation.PSCredential ($username, $pw)
$myfile = [System.IO.File]::ReadAllBytes("C:\Temp\srctest.txt")
$s = New-PSSession -computerName $server -credential $cred
Enter-PSSession $s
Invoke-Command -Session $s -ArgumentList $myfile -Scriptblock {[System.IO.File]::WriteAllBytes("C:\Temp\desttest.txt", $args)}
Write-Host "Completed"
Remove-PSSession $s
}